package com.oneandseven.dajia.service;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.oneandseven.dajia.entity.user.UserBaseInfoEntity;
import com.oneandseven.dajia.repository.user.IUserInfoRepository;
import com.oneandseven.dajia.utils.IdWorker;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.math.BigInteger;
import java.security.SecureRandom;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service
public class WechatService {
    private static final Logger LOG = LoggerFactory.getLogger(WechatService.class);
    private static final int TOKEN_BIT_LENGTH = 130; // 可以根据需要调整位长度
    private static final int RADIX = 32; // 使用32进制来缩短字符串长度
    private static final Integer INIT_CREDIT_COUNT = 3;
    private static final String WECHAT_ACCESS_TOKEN_KEY = "weixin_access_token";
    private static final String WECHAT_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token";
    private static final String WECHAT_LOGIN_URL = "https://api.weixin.qq.com/sns/jscode2session";
    private static final int EXPIRE_TIME_IN_SECONDS = 5400; // 1.5 hours
    private final StringRedisTemplate stringRedisTemplate;
    private CloseableHttpClient httpClient;
    private final ObjectMapper objectMapper = new ObjectMapper();
    private final SecureRandom secureRandom = new SecureRandom();

    private final IdWorker idWorker;
    private final IUserInfoRepository userInfoRepository;

    @Value("${wechat.appid}")
    private String wechatAppId;

    @Value("${wechat.appsecret}")
    private String wechatAppSecret;

    @Autowired
    public WechatService(StringRedisTemplate stringRedisTemplate, IdWorker idWorker,IUserInfoRepository userInfoRepository) {
        this.stringRedisTemplate = stringRedisTemplate;
        this.idWorker = idWorker;
        this.userInfoRepository = userInfoRepository;
    }

    @PostConstruct
    public void init() {
        httpClient = HttpClients.createDefault();
    }

    public String getToken(String code) {
        try {
            String accessToken = getAccessToken();
            String url = String.format("%s?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code&access_token=%s",
                    WECHAT_LOGIN_URL, wechatAppId, wechatAppSecret, code, accessToken);
            HttpGet request = new HttpGet(url);
            String response = EntityUtils.toString(httpClient.execute(request).getEntity());
            LOG.info("jscode2session response: {}", response);
            JsonNode jsonNode = objectMapper.readTree(response);
            if( jsonNode.has("errcode") && jsonNode.get("errcode").asInt() != 0 ) {
                LOG.error("Error while getting jscode2session: {}", response);
                return null;
            }
            String openid = jsonNode.get("openid").asText();
            String sessionKey = jsonNode.get("session_key").asText();
            UserBaseInfoEntity userInfo = userInfoRepository.queryByOpenId(openid);
            String uid;
            if (userInfo == null) {
//                userInfoRepository.saveAndFlush(new UserBaseInfoEntity(openid, new Date()));
                uid = "";
//                userInfoRepository
//                uid = String.idWorker.getId();
//                int cols = userInfoMapper.insertUserInfo(uid, openid, INIT_CREDIT_COUNT, new Date());
//                if (cols != 1) {
//                    LOG.error("Error while inserting userinfo: {}", response);
//                    return null;
//                }
            } else {
                uid = userInfo.getId();
            }
            Map<String,String> sinfo = new HashMap<String,String>();
            sinfo.put("openid",openid);
            sinfo.put("session_key",sessionKey);
            sinfo.put("uid",String.valueOf(uid));
            String token = new BigInteger(TOKEN_BIT_LENGTH, secureRandom).toString(RADIX);
            stringRedisTemplate.opsForValue().set(token, objectMapper.writeValueAsString(sinfo), 7200, TimeUnit.SECONDS);
            return token;
        } catch (Exception e){
            LOG.error("Error while getting token", e);
            return null;
        }
    }

    public String getAccessToken() {
        String accessToken = stringRedisTemplate.opsForValue().get(WECHAT_ACCESS_TOKEN_KEY);
        if (accessToken == null) {
            accessToken = fetchNewAccessToken();
            if (accessToken != null) {
                stringRedisTemplate.opsForValue().set(WECHAT_ACCESS_TOKEN_KEY, accessToken, EXPIRE_TIME_IN_SECONDS, TimeUnit.SECONDS);
            }
        }
        return accessToken;
    }

    private String fetchNewAccessToken() {
        String accessToken = null;
        try {
            String url = String.format("%s?grant_type=client_credential&appid=%s&secret=%s",
                    WECHAT_ACCESS_TOKEN_URL, wechatAppId, wechatAppSecret);
            HttpGet request = new HttpGet(url);
            String response = EntityUtils.toString(httpClient.execute(request).getEntity());
            accessToken = objectMapper.readTree(response).get("access_token").asText();
        } catch (Exception e) {
            LOG.error("Error fetching new access token", e);
        }
        return accessToken;
    }


}